
`include "common_header.verilog"

//  *************************************************************************
//  File : sync_detect_1040
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited. 
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Serge S.
//  info@morethanip.com
//  *************************************************************************
//  Description: 10G Base-R PCS Receive Core : Sync Detect State Machine
//  Version    : $Id: sync_detect_1040.v,v 1.4 2015/07/09 15:26:10 dp Exp $
//  *************************************************************************

module sync_detect_1040 (

   reset,
   clk,
   ck_ena,
   mode40,
   sh_ok,
   sh_val,
   sig_det,
   slip,
   block_lock);

input   reset;          //  asynch reset
input   clk;            //  system clock        
input   ck_ena;         //  clock enable
input   mode40;         //  operate according to 40G/100G(1), else 10G(0)
input   sh_ok;          //  Sync header good or not 
input   sh_val;         //  Sync header valide 
input   sig_det;        //  Signal detect
output   slip;          //  Slip - next candidate
output   block_lock;    //  sync achieved

reg     slip; 
wire    block_lock; 

parameter STM_TYP_RESET_CNT     = 3'd 0;
parameter STM_TYP_TEST_SH       = 3'd 1;
parameter STM_TYP_TEST_SH2      = 3'd 2;
parameter STM_TYP_GOOD64        = 3'd 3;
parameter STM_TYP_SSLIP         = 3'd 4;

reg     [2:0] state; 
reg     [2:0] nextstate; 
reg     [9:0] sh_cnt;   //  Valid Sync Header counter
reg     sh_cnt_63_1023; //  sh_cnt=63 or sh_cnt=1023
reg     [6:0] sh_invalid_cnt; //  Invalid Sync Header counter
reg     block_lock_s;   //  Lock state reached

//  STM
//  ---

always @(posedge reset or posedge clk)
   begin : process_1
   if (reset == 1'b 1)
      begin
      state <= STM_TYP_RESET_CNT;	
      end
   else
      begin
      //if (ck_ena == 1'b 1)
         begin
         if (sig_det == 1'b 0)
            begin
            state <= STM_TYP_RESET_CNT;	
            end
         else if (ck_ena == 1'b 1)
            begin
            state <= nextstate;	
            end
         end
      end
   end

always @(state or sh_ok or sh_val or sh_cnt_63_1023 or sh_invalid_cnt or block_lock_s or mode40)
   begin : process_2
   case (state)
   STM_TYP_RESET_CNT:
      begin
                //  must leave immediately to avoid missing one count.
                //  TEST_SH respects the valid signal anyway
      if (block_lock_s == 1'b 1)
         begin
         nextstate = STM_TYP_TEST_SH2;	
         end
      else
         begin
         nextstate = STM_TYP_TEST_SH;	
         end
      end

   STM_TYP_TEST_SH:
      begin
        //  covers 2 states as we have transitions to VALID_SH within a single clock cycle here
      if (sh_val == 1'b 1 & sh_ok == 1'b 1)
         begin
                //  VALID_SH
                //  --------
         if (sh_cnt_63_1023 == 1'b 1)
            begin
                //  sh_cnt=64
            nextstate = STM_TYP_GOOD64;	//  current sh is the 64th
            end
         else
            begin
            nextstate = STM_TYP_TEST_SH;	
            end
         end
      else if (sh_val == 1'b 1 & sh_ok == 1'b 0 )
         begin
         nextstate = STM_TYP_SSLIP;	
         end
      else      //  sh_val
         begin
         nextstate = STM_TYP_TEST_SH;	
         end
      end

   STM_TYP_TEST_SH2:
      begin
        //  covers 2 states as we have transitions to VALID_SH2 and INVALID_SH within a single clock cycle here
      if (sh_val == 1'b 1 & sh_ok == 1'b 1)
         begin
                //  VALID_SH2
                //  ---------
         if (sh_cnt_63_1023 == 1'b 1)
            begin
                //  sh_cnt=1024
            nextstate = STM_TYP_RESET_CNT;	
            end
         else
            begin
            nextstate = STM_TYP_TEST_SH2;	
            end
         end
      else if (sh_val == 1'b 1 & sh_ok == 1'b 0 )
         begin
                //  INVALID_SH
                //  ----------
                //  40G: the 65th causes slip: if( sh_invalid_cnt=64 ) then
                //  10G: the 16th causes slip: if( sh_invalid_cnt=15 ) then
         if (mode40 == 1'b 1 & sh_invalid_cnt[6] == 1'b 1 |        // 64: then this is the 65th
             mode40 == 1'b 0 & sh_invalid_cnt[3:0] == 4'h F)       // 15: then this is the 16th
            begin
            nextstate = STM_TYP_SSLIP;	
            end
         else if (sh_cnt_63_1023 == 1'b 1 )
            begin
                //  40G: sh_cnt=1024 * sh_invalid_cnt<65
                //  10G: sh_cnt=64 * sh_invalid_cnt < 16
            nextstate = STM_TYP_RESET_CNT;	
            end
         else
            begin
            nextstate = STM_TYP_TEST_SH2;	
            end

         end
      else      //  sh_val
         begin
         nextstate = STM_TYP_TEST_SH2;	
         end
      end

   STM_TYP_SSLIP:
      begin
      nextstate = STM_TYP_RESET_CNT;	
      end

   STM_TYP_GOOD64:
      begin
        //  implicitly runs through the RESET_CNT state directly to TEST_SH2
      nextstate = STM_TYP_TEST_SH2;	
      end

   default:
      begin
      nextstate = STM_TYP_RESET_CNT;	
      end

   endcase
   end

//  Maintain word Counters
//  ----------------------                                
always @(posedge reset or posedge clk)
   begin : process_3
   if (reset == 1'b 1)
      begin
      sh_cnt <= {10{1'b 0}};	
      sh_cnt_63_1023 <= 1'b 0;	
      sh_invalid_cnt <= {7{1'b 0}};	
      end
   else
      begin
      if (sig_det == 1'b 0)
      begin
        sh_cnt <= {10{1'b 0}};	
        sh_cnt_63_1023 <= 1'b 0;	
        sh_invalid_cnt <= {7{1'b 0}};
      end
      else
      begin
      
      if (ck_ena == 1'b 1)
         begin
         if (nextstate == STM_TYP_RESET_CNT | nextstate == STM_TYP_GOOD64)
            begin
                //  slip_s='1'
                //  always start a new window after slip
            sh_cnt <= {10{1'b 0}};	
            end
         else if (sh_val == 1'b 1 )
            begin
                //  maintain 1024-block window. Automatically wrapping at 1023
            sh_cnt <= sh_cnt + 10'd 1;	
            end

                //  create flag for STM showing if now the 64th or the 1024th is to be checked. The flag is used
                //  for both, as these conditions are unambiguous, used in other STM states (TEST_SH and TEST_SH2).
         if (state == STM_TYP_RESET_CNT | state == STM_TYP_GOOD64)
            begin
            sh_cnt_63_1023 <= 1'b 0;	
            end
         else if (sh_val == 1'b 1 & (state == STM_TYP_TEST_SH & sh_cnt == 10'd 62 | 
                                     state == STM_TYP_TEST_SH2 & mode40 == 1'b 0 & sh_cnt == 10'd 62 | 
                                     state == STM_TYP_TEST_SH2 & mode40 == 1'b 1 & sh_cnt == 10'd 1022) )
            begin
            sh_cnt_63_1023 <= 1'b 1;	
            end

         if (nextstate == STM_TYP_RESET_CNT )
            begin
            sh_invalid_cnt <= {7{1'b 0}};	
            end
         else if (sh_val == 1'b 1 & sh_ok == 1'b 0 )
            begin
            sh_invalid_cnt <= sh_invalid_cnt + 7'd 1;	
            end

         end
      end
   end

end
//  Output Control
//  --------------
always @(posedge reset or posedge clk)
   begin : process_4
   if (reset == 1'b 1)
      begin
      block_lock_s <= 1'b 0;	//  Lock state reached
      slip <= 1'b 0;	//  slip mux
      end
   else
      begin
      if  (sig_det == 1'b 0) 
        begin
        block_lock_s <= 1'b 0;	//  Lock state reached
        slip <= 1'b 0;	//  slip mux
        end        
      else if (ck_ena == 1'b 1)
         begin

         if (nextstate == STM_TYP_SSLIP)
            begin
            slip <= 1'b 1;	
            end
         else
            begin
            slip <= 1'b 0;	
            end

         if (sig_det == 1'b 0 | nextstate == STM_TYP_SSLIP)
            begin
            block_lock_s <= 1'b 0;	
            end
         else if (nextstate == STM_TYP_GOOD64 )
            begin
            block_lock_s <= 1'b 1;	
            end

         end
      end
   end

assign block_lock = block_lock_s;      

endmodule // module sync_detect

